class_name Ball
extends AnimatableBody2D


#足球弹跳系数
const BOUNCINESS := 0.8

#超出这个值，我们将传抛物线球
const DISTANCE_HIGH_PASS := 130

#铲球锁定
const DURATIN_TUMBLE_LOCK := 200
#传球锁定
const DURATIN_PASS_LOCK := 500

#比赛开始开球
const KICKOFF_PASS_DISTANCE := 30.0

#球被非当前玩家行为导致的脱离控制，球的弹跳高度
const TUMBLE_HEIGHT_VELOCITY := 3.0



enum State{CARRIED,FREEFORM,SHOT}



@export var friction_air : float
@export var friction_ground : float


@onready var animation_player : AnimationPlayer = %AnimationPlayer
@onready var ball_sprite : Sprite2D = %BallSprite
@onready var player_detection_area : Area2D = %PlayerDetectionArea
#球自由转态时，玩家会一窝蜂的冲向球，这点不好，球检测玩家密度
@onready var player_proxinmity_area : Area2D = %PlayerProximityArea

@onready var scoring_raycast :RayCast2D = %ScoringRayCast
@onready var shot_particles :GPUParticles2D = %ShotParticles




var carrier : Player = null
var current_state : BallState = null
var height : float = 0.0
var height_velocity : float = 0.0
var spawn_position := Vector2.ZERO
var state_factory := BallStateFactory.new()
var velocity := Vector2.ZERO


func _ready() -> void:
	switch_state(State.FREEFORM)
	spawn_position = position
	GameEvents.team_reset.connect(on_team_reset.bind())
	GameEvents.kickoff_start.connect(on_kickoff_start.bind())


func _process(_delta: float) -> void:
	ball_sprite.position = Vector2.UP * height
	scoring_raycast.rotation = velocity.angle()



func switch_state(state:State,data :BallStateData = BallStateData.new()) -> void:
	if current_state != null:
		current_state.queue_free()
	current_state = state_factory.get_fresh_state(state)
	current_state.setup(self,data,player_detection_area,carrier,animation_player,ball_sprite,shot_particles)
	current_state.state_transition_reuested.connect(switch_state.bind())
	current_state.name = "BallStateMachine: " + str(state)
	call_deferred("add_child",current_state)



func shoot(shot_velocity:Vector2) -> void:
	velocity = shot_velocity
	carrier = null
	switch_state(Ball.State.SHOT)

#球翻滚，在失去球控制时调用的方法
func tumble(tumble_velocity:Vector2) -> void:
	velocity = tumble_velocity
	carrier = null
	height_velocity = TUMBLE_HEIGHT_VELOCITY
	switch_state(Ball.State.FREEFORM,BallStateData.build().set_lock_duration(DURATIN_TUMBLE_LOCK))



#这里对阻力进行了计算，但需要注意的是，这里只有对x轴方向的阻力，y轴方向的被省略了，本游戏没有问题，但这带来了通用方面的后果
func pass_to(destination:Vector2,lock_duration:int = DURATIN_PASS_LOCK) -> void:
	var direction := position.direction_to(destination)
	var distance := position.distance_to(destination)
	var instensity := sqrt(2* distance*friction_ground)
	velocity = instensity * direction
	if (distance > DISTANCE_HIGH_PASS):
		#height_velocity = BallState.GRAVITY * distance / (2*instensity)
		height_velocity = BallState.GRAVITY * distance / (1.7*instensity)

	carrier = null
	switch_state(Ball.State.FREEFORM,BallStateData.build().set_lock_duration(lock_duration))


func stop() -> void:
	velocity = Vector2.ZERO

#球是不是可互動
func can_air_interact() -> bool:
	return current_state !=null and current_state.can_air_interact()

#球是不是自由狀態
func is_freeform() -> bool:
	return current_state !=null and current_state is BallStateFreeform



func can_air_connect(air_connect_min_height : float,air_connect_max_height : float) -> bool:
	return height >= air_connect_min_height and height <= air_connect_max_height


func is_headed_for_scoring_area(scoring_area:Area2D)->bool:
	if not scoring_raycast.is_colliding():
		return false
	return scoring_raycast.get_collider() == scoring_area
	
	

func get_proximity_teammates_count(country:String) -> int :
	var players := player_proxinmity_area.get_overlapping_bodies()
	return players.filter(func(p:Player): return p.country == country).size()

	
	
func on_kickoff_start() -> void:
	pass_to(spawn_position + Vector2.DOWN * KICKOFF_PASS_DISTANCE,0)


func on_team_reset() ->void:
	position = spawn_position
	velocity = Vector2.ZERO
	switch_state(State.FREEFORM)
